{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def loadDataSet(filename):\n",
    "    '''\n",
    "    读取数据集\n",
    "\n",
    "    Args:\n",
    "        filename: 文件名\n",
    "    Returns:\n",
    "        dataMat: 数据样本矩阵    \n",
    "    '''\n",
    "    dataMat = []\n",
    "    with open(filename, 'rb') as f:\n",
    "        for line in f:\n",
    "            # 读取的字节流需要先解码成utf-8再处理\n",
    "            eles = list(map(float, line.decode('utf-8').strip().split('\\t')))\n",
    "            dataMat.append(eles)\n",
    "    return dataMat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def distEclud(vecA, vecB):\n",
    "    '''\n",
    "    计算两向量的欧氏距离\n",
    "\n",
    "    Args:\n",
    "        vecA: 向量A\n",
    "        vecB: 向量B\n",
    "    Returns:\n",
    "        欧式距离\n",
    "    '''\n",
    "    return np.sqrt(np.sum(np.power(vecA-vecB,2)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def randCent(dataSet, k):\n",
    "    '''\n",
    "    随机生成k个聚类中心\n",
    "\n",
    "    Args:\n",
    "        dataSet: 数据集\n",
    "        k: 簇数目\n",
    "    Returns:\n",
    "        centroids: 聚类中心矩阵    \n",
    "    '''\n",
    "    m, _ = dataSet.shape\n",
    "    # 随机从数据集中选几个作为初始聚类中心\n",
    "    centroids = dataSet.take(np.random.choice(80,k), axis=0)\n",
    "    return centroids"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def kMeans(dataSet, k, maxIter = 5):\n",
    "    '''\n",
    "    K-Means\n",
    "\n",
    "    Args:\n",
    "        dataSet: 数据集\n",
    "        k: 聚类数\n",
    "    Returns:\n",
    "        centroids: 聚类中心\n",
    "        clusterAssment: 点分配结果\n",
    "    '''\n",
    "    # 随机初始化聚类中心\n",
    "    centroids = randCent(dataSet, k)\n",
    "    init_centroids = centroids.copy()\n",
    "    \n",
    "    m, n = dataSet.shape\n",
    "    \n",
    "    # 点分配结果：第一列指明样本所在的簇，第二列指明该样本到聚类中心的距离\n",
    "    clusterAssment = np.mat(np.zeros((m,2)))\n",
    "    \n",
    "    # 标识聚类中心是否仍在变化\n",
    "    clusterChanged = True\n",
    "    \n",
    "    # 直至聚类中心不再变化\n",
    "    iterCount = 0\n",
    "    while clusterChanged and iterCount < maxIter:\n",
    "        iterCount += 1\n",
    "        clusterChanged = False\n",
    "        # 分配样本到簇\n",
    "        for i in range(m):\n",
    "            # 计算第i个样本到各个聚类中心的距离\n",
    "            minIndex = 0\n",
    "            minDist = np.inf\n",
    "            for j in range(k):\n",
    "                dist = distEclud(dataSet[i,:], centroids[j,:])\n",
    "                if dist < minDist:\n",
    "                    minIndex = j\n",
    "                    minDist = dist\n",
    "            # 任何一个样本的类簇分配发生变化则认为变化\n",
    "            if clusterAssment[i,0] != minIndex:\n",
    "                clusterChanged = True\n",
    "            clusterAssment[i,:] = minIndex, minDist**2\n",
    "            \n",
    "        # 刷新聚类中心：移动聚类中心点到所有簇的均值位置\n",
    "        for cent in range(k):\n",
    "            # 通过数组过滤得到簇中的点\n",
    "            # matrix.A 是将matrix-->array\n",
    "            ptsInCluster = dataSet[np.nonzero(clusterAssment[:,0].A == cent)[0]]\n",
    "            if ptsInCluster.shape[0] > 0:\n",
    "                # 计算均值并移动\n",
    "                centroids[cent, :] = np.mean(ptsInCluster, axis=0)\n",
    "    return centroids, clusterAssment, init_centroids"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataMat = np.mat(loadDataSet('data/testSet.txt'))\n",
    "m, n = np.shape(dataMat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "set_k = 4\n",
    "centroids, clusterAssment, init_centroids = kMeans(dataMat, set_k)\n",
    "\n",
    "clusterCount = np.shape(centroids)[0]\n",
    "clusterCount"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 我们这里只设定了最多四个簇的样式，所以前面如果set_k设置超过了4，后面就会出现index error\n",
    "patterns = ['o', 'D', '^', 's']\n",
    "colors = ['b', 'g', 'y', 'black']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x25396e5ac88>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure()\n",
    "title = 'kmeans with k={}'.format(set_k)\n",
    "ax = fig.add_subplot(111, title=title)\n",
    "for k in range(clusterCount):\n",
    "    # 绘制聚类中心\n",
    "    ax.scatter(centroids[k,0], centroids[k,1], color='r', marker='+', linewidth=20)\n",
    "    # 绘制初始聚类中心\n",
    "    ax.scatter(init_centroids[k,0], init_centroids[k,1], color='purple', marker='*', linewidth=10 )\n",
    "    for i in range(m):\n",
    "        # 绘制属于该聚类中心的样本\n",
    "        ptsInCluster = dataMat[np.nonzero(clusterAssment[:,0].A==k)[0]]\n",
    "        ax.scatter(ptsInCluster[:,0].flatten().A[0], ptsInCluster[:,1].flatten().A[0], color=colors[k], marker=patterns[k])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
